package com.cy.stone.framework.web.filter;

import com.cy.stone.common.errorcode.SysErrorCode;
import com.feiniaojin.gracefulresponse.GracefulResponseException;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.util.Enumeration;

/**
 * sql防注入过滤器
 * @author Wings
 * @since 2023-12-16
 */
@Configuration
@WebFilter(urlPatterns = "/*", filterName = "sqlFilter")
@Slf4j
public class SqlFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 获得所有请求参数名
        Enumeration<String> names = servletRequest.getParameterNames();
        StringBuilder sql = new StringBuilder();
        while(names.hasMoreElements()) {
            // 得到参数名
            String name = names.nextElement();
            // 得到参数对应的值
            String[] values = servletRequest.getParameterValues(name);
            for (String value : values) {
                sql.append(value);
            }
        }
        if (sqlValidate(String.valueOf(sql))) {
            log.info("------有SQL注入风险，请求被拦截！！！-----");
            throw new GracefulResponseException(SysErrorCode.ILLEGAL_TEXT.getCode(), SysErrorCode.ILLEGAL_TEXT.getMessage());
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    protected static boolean sqlValidate(String str) {
        // 统一转为小写
        String s = str.toLowerCase();
        // 过滤掉的sql关键字，特殊字符前面需要加\\进行转义
        String badStr =
                "select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|count|master|drop|execute|table|"+
                        "sitename|xp_cmdshell|like|from|grant|use|group_concat|column_name|" +
                        "information_schema.columns|table_schema|union|where|order|by|" +
                        "'\\*|;|-|--|\\+|,|//|/|%|#";
        //使用正则表达式进行匹配
        return s.matches(badStr);
    }
}
